/*
 * Copyright 2010 Dovado FZ-LLC
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *       http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package com.dovado.dovadoremote;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.UnsupportedEncodingException;
import java.net.URI;
import java.util.ArrayList;
import java.util.List;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

import org.apache.http.HttpEntity;
import org.apache.http.HttpResponse;
import org.apache.http.NameValuePair;
import org.apache.http.client.ClientProtocolException;
import org.apache.http.client.entity.UrlEncodedFormEntity;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.cookie.Cookie;
import org.apache.http.impl.client.DefaultHttpClient;
import org.apache.http.message.BasicNameValuePair;
import org.apache.http.params.BasicHttpParams;
import org.apache.http.params.HttpConnectionParams;
import org.apache.http.params.HttpParams;
import org.apache.http.protocol.HTTP;

public class Webactivator {

	/*
	 * Returns empty String if activation was successful, error message
	 * otherwise
	 */
	public static String activate() {

		/*
		 * Set timeout until connection established:
		 */
		HttpParams httpParameters = new BasicHttpParams();
		int timeoutConnection = 15000;
		HttpConnectionParams.setConnectionTimeout(httpParameters,
				timeoutConnection);
		/*
		 * Set timeout for waiting on data:
		 */
		int timeoutSocket = 30000;
		HttpConnectionParams.setSoTimeout(httpParameters, timeoutSocket);
		DefaultHttpClient httpclient = new DefaultHttpClient(httpParameters);
		/*
		 * clear cookies just in case:
		 */
		httpclient.getCookieStore().clear();
		/*
		 * Get cookies
		 */

		HttpGet httpget = new HttpGet("http://" + Communicator.getHost(""));
		HttpResponse response = null;
		try {
			response = httpclient.execute(httpget);
		} catch (ClientProtocolException e) {
			return "Protocol Error";
		} catch (IOException e) {
			return "I/O Error";
		} catch (Exception e) {
			return "Unknown error";
		}
		HttpEntity entity = response.getEntity();

		if (entity != null) {
			try {
				entity.consumeContent();
			} catch (IOException e) {
				return "I/O Error";
			}
		}
		// System.err.println("Initial set of cookies:");

		List<Cookie> cookies = httpclient.getCookieStore().getCookies();
		if (cookies.isEmpty()) {
			System.err.println("No cookies found");
		} else {
			for (int i = 0; i < cookies.size(); i++) {
				System.err.println("- " + cookies.get(i).toString());
			}
		}

		/*
		 * Login
		 */
		// System.err.println("DEBUG: getting http://"+Communicator.getHost()+"/cgi-bin/login.cgi");
		HttpPost httpost = new HttpPost("http://" + Communicator.getHost()
				+ "/cgi-bin/login.cgi");
		List<NameValuePair> nvps = new ArrayList<NameValuePair>();
		nvps.add(new BasicNameValuePair("LOGINUNAME", Communicator
				.getUsername()));
		nvps.add(new BasicNameValuePair("LOGINPASSWD", Communicator
				.getPassword()));
		httpost.setHeader("Accept", "*/*");
		httpost.setHeader("Expect", null);
		try {
			httpost.setEntity(new UrlEncodedFormEntity(nvps, HTTP.UTF_8));
		} catch (UnsupportedEncodingException e) {
			return "Encoding error";
		}

		try {
			response = httpclient.execute(httpost);
		} catch (ClientProtocolException e) {
			return "Protocol Error";
		} catch (IOException e) {
			return "I/O Error";
		} catch (Exception e) {
			return "Unknown error";
		}
		entity = response.getEntity();

		if (entity != null) {
			try {
				entity.consumeContent();
			} catch (IOException e) {
				return "I/O error";
			}
		}
		Cookie umr_session_cookie = null;
		System.err.println("Post logon cookies:");
		cookies = httpclient.getCookieStore().getCookies();
		if (cookies.isEmpty()) {
			System.err.println("None");
		} else {
			for (int i = 0; i < cookies.size(); i++) {
				System.err.println("- " + cookies.get(i).toString());
				if (cookies.get(i).getName().equalsIgnoreCase("umrsession")) {
					umr_session_cookie = cookies.get(i);
				}
			}
		}

		/*
		 * Fetch home-page and parse firmware version
		 */
		// System.err.println("DEBUG: getting http://"+Communicator.getHost()+"/cgi-bin/getcfg.cgi?home");
		httpost.setURI(URI.create("http://" + Communicator.getHost()
				+ "/cgi-bin/getcfg.cgi?home"));
		httpost.setHeader("Cookie", umr_session_cookie.getName() + "="
				+ umr_session_cookie.getValue());
		try {
			response = httpclient.execute(httpost);
		} catch (ClientProtocolException e) {
			return "Protocol Error";
		} catch (IOException e) {
			return "I/O Error";
		} catch (Exception e) {
			return "Unknown error";
		}
		// entity = response.getEntity();
		BufferedReader in = null;
		try {
			in = new BufferedReader(new InputStreamReader(response.getEntity()
					.getContent()));
		} catch (IllegalStateException e) {
			return "Error while logging in";
		} catch (IOException e) {
			return "I/O Error";
		}
		StringBuffer sb = new StringBuffer("");
		String line = "";
		String NL = System.getProperty("line.separator");
		try {
			while ((line = in.readLine()) != null) {
				sb.append(line + NL);
			}
		} catch (IOException e) {
			return "I/O Error";
		}
		try {
			in.close();
		} catch (IOException e) {
			return "I/O Error";
		}
		String page = sb.toString();
		// Extract Firmware version using regular expressions:
		Pattern p = Pattern
				.compile(".*<tr><td><b>Firmware Revision:</b></td><td>(.*)</td></tr>.*");
		Matcher m = p.matcher(page);

		int firmwareversion = 0;
		// if we find a match, get the group
		if (m.find()) {
			// we're only looking for one group, so get it
			String firmwareversion_string = m.group(1).substring(0, 5);
			firmwareversion = Integer.parseInt(removeChar(
					firmwareversion_string, '.'));

			// print the group out for verification
			// System.err.format("'%s'\n", theGroup);
		}

		if (firmwareversion < 430) {
			return "firmware";
		} else if (firmwareversion >= 430) {
			/*
			 * Ok, now we can enable the API:
			 */

			// System.err.println("DEBUG: getting http://"+Communicator.getHost()+"/cgi-bin/getcfg.cgi?extcmd+enablelanapi");
			httpost.setURI(URI.create("http://" + Communicator.getHost()
					+ "/cgi-bin/getcfg.cgi?extcmd+enablelanapi"));
			httpost.setHeader("Cookie", umr_session_cookie.getName() + "="
					+ umr_session_cookie.getValue());
			try {
				response = httpclient.execute(httpost);
			} catch (ClientProtocolException e) {
				return "Protocol Error";
			} catch (IOException e) {
				return "I/O Error";
			} catch (Exception e) {
				return "Unknown error";
			}

			// When HttpClient instance is no longer needed,
			// shut down the connection manager to ensure
			// immediate deallocation of all system resources
			httpclient.getConnectionManager().shutdown();
			// return true;
			return "";
		} else {
			return "failed";
		}
	}

	/*
	 * Removes a char in a string (yes, I know this is a bad way of handling
	 * strings):
	 */
	public static String removeChar(String s, char c) {

		String r = "";

		for (int i = 0; i < s.length(); i++) {
			if (s.charAt(i) != c) {
				r += s.charAt(i);
			}
		}

		return r;
	}
}
